import protobuf from 'protobufjs';
import { proto } from '../src/zotero/app_proto2_pb.js';

// TODO: Highlights shouldn't be allowed to be outside of page view


function errObject(err) {
	return JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err)));
}

let cmapCache = {};
async function cmapProvider(name) {
	if (cmapCache[name]) {
		return cmapCache[name];
	}
	let data = await query('FetchBuiltInCMap', name);
	cmapCache[name] = data;
	return data;
}

let fontCache = {};
async function standardFontProvider(filename) {
  // 如果内存中有缓存,直接返回
  if (fontCache[filename]) {
    return fontCache[filename];
  }

  // 对于标准字体,使用原有逻辑
  let data = await query('FetchStandardFontData', filename);
  fontCache[filename] = data;
  return data;
}

// 添加protobuf相关函数
async function encodeProtobufMessage(data, protoDefinition) {
    try {
        // 从字符串加载proto定义
        const root = protobuf.parse(protoDefinition).root;

        // 获取消息类型
        const MessageType = root.lookupType('proto.search.SearchRequest');

        // 验证数据
        const errMsg = MessageType.verify(data);
        if (errMsg) {
            throw Error(errMsg);
        }

        // 创建消息实例
        const message = MessageType.create(data);

        // 编码数据
        const encodedData = MessageType.encode(message).finish();

        // 添加长度前缀
        const length = encodedData.length;
        const bufferSize = length + 5;
        const tData = new Uint8Array(bufferSize);

        // 设置头部
        let pos5 = length;
        let pos4 = Math.floor(length/256);
        if(length > 255) {
            pos5 = length - 256;
        }
        tData.set(new Uint8Array([0, 0, 0, pos4, pos5]), 0);

        // 设置实际数据
        if (length > 0) {
            tData.set(encodedData, 5);
        }

        return tData;
    } catch (error) {
        console.error('Protobuf编码失败:', error);
        throw error;
    }
}

async function decodeSearchRspProtobufMessage(buffer) {
    try {
        // 检查buffer长度
        if (!buffer || buffer.byteLength < 5) {
            throw new Error('无效的buffer数据');
        }

        // 将ArrayBuffer转换为Uint8Array
        const responseData = new Uint8Array(buffer);

        // 解析长度（前5字节）
        const lengthHex = Array.from(responseData.slice(0, 5))
            .map(b => b.toString(16).padStart(2, '0'))
            .join('');
        const length = parseInt(lengthHex, 16);

        // 提取实际数据
        const result = responseData.slice(5, 5 + length);

        // 使用直接导入的SearchService_SearchResponse
        let obj = proto.search.SearchService_SearchResponse.deserializeBinary(result);
		let jsResult = obj.toObject();
        console.info("SearchService_SearchResponse 解码的数据", jsResult);


        // 转换为普通JavaScript对象
        return jsResult;
    } catch (error) {
        console.error('SearchService_SearchResponse解码失败:', error);
        throw error;
    }
}

async function decodeSearchDetailRspProtobufMessage(buffer) {
    try {
        // 检查buffer长度
        if (!buffer || buffer.byteLength < 5) {
            throw new Error('无效的buffer数据');
        }

        // 将ArrayBuffer转换为Uint8Array
        const responseData = new Uint8Array(buffer);

        // 解析长度（前5字节）
        const lengthHex = Array.from(responseData.slice(0, 5))
            .map(b => b.toString(16).padStart(2, '0'))
            .join('');
        const length = parseInt(lengthHex, 16);

        // 提取实际数据
        const result = responseData.slice(5, 5 + length);

        // 使用直接导入的SearchService_SearchResponse
        let obj = proto.search.WwwService_ExportResponse.deserializeBinary(result);
		let jsResult = obj.toObject();
        console.info("WwwService_ExportResponse解码的数据", jsResult);


        // 转换为普通JavaScript对象
        return jsResult;
    } catch (error) {
        console.error('WwwService_ExportResponse解码失败:', error);
        throw error;
    }
}

if (typeof self !== 'undefined') {
	let promiseID = 0;
	let waitingPromises = {};

	self.query = async function (action, data, transfer) {
		return new Promise(function (resolve) {
			promiseID++;
			waitingPromises[promiseID] = resolve;
			self.postMessage({ id: promiseID, action, data }, transfer);
		});
	};

	self.onmessage = async function (e) {
		let message = e.data;

		if (message.responseID) {
			let resolve = waitingPromises[message.responseID];
			if (resolve) {
				resolve(message.data);
			}
			return;
		}

		if (message.action === 'encodeProtobuf') {
			try {
				const encodedData = await encodeProtobufMessage(
					message.data.data,
					message.data.protoDefinition
				);
				self.postMessage({ responseID: message.id, data: encodedData }, [encodedData.buffer]);
			}
			catch (e) {
				self.postMessage({
					responseID: message.id,
					error: errObject(e)
				});
			}
		}
		else if (message.action === 'decodeSearchRspProtobufMessage') {
			try {
				const decodedData = await decodeSearchRspProtobufMessage(
					message.data.buffer,
					message.data.protoDefinition
				);
				self.postMessage({ responseID: message.id, data: decodedData });
			}
			catch (e) {
				self.postMessage({
					responseID: message.id,
					error: errObject(e)
				});
			}
		}
		else if (message.action === 'decodeSearchDetailRspProtobufMessage') {
			try {
				const decodedData = await decodeSearchDetailRspProtobufMessage(
					message.data.buffer,
					message.data.protoDefinition
				);
				self.postMessage({ responseID: message.id, data: decodedData });
			}
			catch (e) {
				self.postMessage({
					responseID: message.id,
					error: errObject(e)
				});
			}
		}
	}
}

export {
	encodeProtobufMessage,
	decodeSearchRspProtobufMessage,
	decodeSearchDetailRspProtobufMessage
};
